/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

package com.huawei.api.task;

import com.huawei.api.bean.ClientParameter;
import com.huawei.api.bean.CmdParameter;
import com.huawei.api.bean.Context;
import com.huawei.api.bean.Defect;
import com.huawei.api.bean.FileInfo;
import com.huawei.api.bean.Language;
import com.huawei.api.bean.Rule;
import com.huawei.api.builder.FileCfgBuilder;
import com.huawei.api.builder.LanguageCfgBuilder;
import com.huawei.api.builder.RuleCfgBuilder;
import com.huawei.api.constants.Constant;
import com.huawei.api.constants.ProjectConstant;
import com.huawei.api.exception.BaseCustomerException;
import com.huawei.api.handler.FileHandler;
import com.huawei.api.handler.RuleHandler;
import com.huawei.api.utils.FileUtil;
import com.huawei.api.utils.PathUtil;
import com.huawei.api.utils.ReportUtil;
import com.huawei.api.utils.StringConvertUtil;

import com.alibaba.fastjson.JSON;

import lombok.Data;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.core.util.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 数据分析任务
 *
 * @since 2023/10/28
 */
@Data
public class AnalyzeTask implements Task {
    private static final Logger LOGGER = LoggerFactory.getLogger(AnalyzeTask.class);

    private final Context context;

    private final ClientParameter clientParameter;

    private final List<CmdParameter> cmdParameters;

    public AnalyzeTask(ClientParameter clientParameter) {
        this.clientParameter = clientParameter;
        this.context = new Context();
        this.cmdParameters = new ArrayList<>();
    }

    public void execute() throws BaseCustomerException {
        LOGGER.info("----------------------------AnalyzeTask start------------------------------");
        //检测之前,初始化配置，获取构建cmd所需参数
        this.preExecute();
        //构建cmd命令
        this.postExecute();
        //将cmd分发到各个执行器
        // this.afterExecute();
    }

    /**
     * 构造命令之前获取相关的配置信息
     *
     * @throws BaseCustomerException 异常
     */
    private void preExecute() throws BaseCustomerException {
        // 项目路径通过传进来，之前采用user.dir。获取的路径时不正确的
        String pluginPath = PathUtil.getSystemPath();
        LOGGER.info("pluginPath : {}", pluginPath.replace("/", "="));
        // 初始化规则配置文件，配置文件中包含语言、规则、检测文件配置;以config为准,如果配置文件不存在则以默认为准
        String ruleConfigPath = pluginPath + File.separator + ProjectConstant.FileConfigConstant.CONFIG + File.separator
            + ProjectConstant.FileConfigConstant.RULE_CONFIG;
        // 获取配置的规则
        RuleCfgBuilder ruleCfgBuilder = new RuleCfgBuilder(ruleConfigPath);
        ruleCfgBuilder.build();

        // 初始化语言配置文件
        String languageConfigPath = pluginPath + File.separator + ProjectConstant.FileConfigConstant.CONFIG
            + File.separator + ProjectConstant.FileConfigConstant.LANGUAGE_CONFIG;
        LanguageCfgBuilder languageCfgBuilder = new LanguageCfgBuilder(languageConfigPath);
        languageCfgBuilder.build();

        // 初始化检测配置文件 【工具需要文件夹，因此不需要拆分文件给到工具】
        String fileConfigPath = pluginPath + File.separator + ProjectConstant.FileConfigConstant.CONFIG + File.separator
            + ProjectConstant.FileConfigConstant.FILE_CONFIG;
        FileCfgBuilder fileCfgBuilder = new FileCfgBuilder(fileConfigPath,
            new FileInfo(clientParameter.getSource(), clientParameter.getIncludeFiles(),
                clientParameter.getExcludeFiles()));
        fileCfgBuilder.build();

        // 获取文件列表
        FileHandler fileHandler = new FileHandler(fileCfgBuilder.getFileInfo());
        fileHandler.handle();

        // 获取规则列表
        RuleHandler ruleHandler = new RuleHandler(clientParameter, ruleCfgBuilder);
        ruleHandler.handle();
        LOGGER.info("formatcheck load configs : rules={},languages={}", JSON.toJSON(ruleCfgBuilder),JSON.toJSON(languageCfgBuilder));

        for (Language language : languageCfgBuilder.getLanguages()) {
            // 规则划分
            Set<String> collect = diffUtils(ruleCfgBuilder, ruleHandler, language);
            if (ObjectUtils.isEmpty(collect)) {
                continue;
            }
            CmdParameter cmdParameter = new CmdParameter();
            cmdParameter.setLanguage(language.getLanguage());
            cmdParameter.setToolName(language.getToolName());
            // todo按照长度分组
            cmdParameter.setFilePaths(new ArrayList<>());
            cmdParameter.setCheckers(collect);
            cmdParameter.setLocalToolPath(language.getLocalToolPath());
            cmdParameter.setLocalToolCmd(language.getLocalToolCmd());
            cmdParameter.setCodeArtsToolPath(language.getCodeArtsToolPath());
            cmdParameter.setCodeArtsToolCmd(language.getCodeArtsToolCmd());
            cmdParameter.setCodeArtsToolLinuxCmd(language.getCodeArtsToolLinuxCmd());
            cmdParameter.setType(clientParameter.getType());
            cmdParameter.setBasePath(language.getBasePath());
            cmdParameter.setPluginPath(pluginPath); // 项目运行的路径
            cmdParameter.setSource(clientParameter.getSource()); // 扫描文件的路径
            cmdParameter.setParamFilePath(clientParameter.getParamFilePath());
            cmdParameter.setBranch(clientParameter.getBranch());
            cmdParameter.setOutput(clientParameter.getOutput());
            cmdParameter.setToolPath(clientParameter.getToolPath());
            cmdParameter.setCheckerPath(clientParameter.getChecker());
            this.cmdParameters.add(cmdParameter);
        }
        LOGGER.info("<<< AnalyzeTask preExecute cmdParameters size={} ", cmdParameters.size());
    }

    private Set<String> diffUtils(RuleCfgBuilder ruleCfgBuilder, RuleHandler ruleHandler, Language language) {
        List<String> list = ruleCfgBuilder.getDefaultRules()
            .stream()
            .filter(rule -> language.getToolName().startsWith(rule.getCategory()))
            .map(Rule::getChecker)
            .collect(Collectors.toList());
        Set<String> checkList = ruleHandler.getCheckers();
        Set<String> diffRules = checkList.stream()
            .filter(checker -> list.contains(checker))
            .collect(Collectors.toSet());
        LOGGER.info("<<< AnalyzeTask diffUtils defaultRules={} ,checkRules={}, diffRules={} ", JSON.toJSON(list),
            JSON.toJSON(checkList), JSON.toJSON(diffRules));
        return diffRules;
    }

    private void postExecute() throws BaseCustomerException {
        FormatCheckTask formatCheckTask = new FormatCheckTask(cmdParameters, clientParameter.getOutput());
        formatCheckTask.execute();
        List<Defect> defects = readResult(clientParameter.getOutput());
        context.getDefects().addAll(defects);
    }

    private List<Defect> readResult(String output) {
        String filePath = output + "result.json";
        LOGGER.info("formatcheck readResult Result filePath={},", StringConvertUtil.convert(filePath, "="));
        try {
            String content = FileUtil.getFileContent(filePath);
            List<Defect> defects = JSON.parseArray(content, Defect.class);
            LOGGER.info("AnalyzeTask readResult result is={},size={}", content, defects.size());
            return defects;
        } catch (BaseCustomerException e) {
            LOGGER.info("AnalyzeTask readResult error ", e);
        }
        return Collections.EMPTY_LIST;
    }

    private void afterExecute() throws BaseCustomerException {
        String output = clientParameter.getOutput();
        if (StringUtils.isBlank(output)) {
            output = PathUtil.getSystemPath() + File.separator + Constant.DEFAULT_OUTPUT_FILE;
        }
        ReportUtil.writeReport(context.getDefects(), output);
    }
}
